// HTML5 MNet runtime.
//
// Copyright 2011-2012 Martin Leidel, all rights reserved.
//
// This software is provided 'as-is', without any express or implied
// warranty.  In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.

// *****************************************************************************
// *** HTTP stuff
// *****************************************************************************

var _httpResponse;

MNet_Http = function()
{
}

MNet_Http.prototype.Get = function( url, timeoutConnection, timeoutSocket )
{
  try
  {
    var client = new XMLHttpRequest();
    client.open( "GET", url, false );
    client.send( null );
    _httpResponse = client.responseText;
    return _httpResponse;
  }
  catch( e )
  {
  }
}

MNet_Http.prototype.AGet = function( url, timeoutConnection, timeoutSocket )
{
  // not implemented
}

MNet_Http.prototype.GetResult = function()
{
  return _httpResponse;
}

// *****************************************************************************
// *** Pubnub stuff
// *** Big thanks goes to Skn3 for this!
// *****************************************************************************

// globals
var _pubnubInitSuccess = false;
var _pubnubPublishKey = "";
var _pubnubSubscribeKey = "";
var _pubnubChannel = 0;
//classes
//class channel

function MNet_PubnubChannel( id )
{
  // --- channel constructor ---
  // fields
  this.channel = id;
  this.isConnected = false;
  this.isFetching = 0;
  this.messages = [];
  this.history = [];

  // subscribe to channel
  var chan = this;
  PUBNUB.subscribe(
  {
    channel: this.channel,
    restore: false,
    callback: function( message )
    {
      // convert to string and add to messages
      var msg = JSON.stringify( message.MNetKey );
      chan.messages.push( String( msg ) );
    },
    disconnect: function() 
    {
      chan.isConnected = false;
    },
    reconnect: function()
    {
      chan.isConnected = true;
    },
    connect: function()
    {
      chan.isConnected = true;
    },
    error: function( e )
    {
      // alert("error = "+e);
    }
  } );
}

// class channel - methods
MNet_PubnubChannel.prototype.Send = function( value )
{
  // --- send a message on this channel ---
  var msg = { "MNetKey": value };
  PUBNUB.publish(
  {
    channel: this.channel,
    message: msg,
    callback: function( info )
    {
      if( info[0] == 0 )
      {
        // failed
      }
    }
  } );
}

MNet_PubnubChannel.prototype.Connected = function()
{
  // --- return true if connected ---
  return this.isConnected;
}

MNet_PubnubChannel.prototype.Fetch = function( amount )
{
  // --- fetch items from the history ---
  this.isFetching++;
  this.history = [];

  // request history from pubnub
  var chan = this;
  PUBNUB.history(
  {
    channel: this.id,
    limit: amount
  },
  function( messages )
  {
    // success
    chan.isFetching--;

    // convert to strings and add to history
    for( var index = 0; index < messages.length; index++ )
      chan.history.push( String( messages[index] ) );
  } );
}

MNet_PubnubChannel.prototype.Fetching = function()
{
  // --- returns true if currently fetching history ---
  return ( this.isFetching > 0 );
}

MNet_PubnubChannel.prototype.FetchAvailable = function()
{
  // --- returns the number of history waiting ---
  return this.history.length;
}

MNet_PubnubChannel.prototype.NextFetch = function()
{
  // --- returns a history if there is one ---
  if( this.history.length > 0 )
    return this.history.shift();
}

MNet_PubnubChannel.prototype.MessageAvailable = function()
{
  // --- returns the number of messages waiting ---
  return this.messages.length;
}

MNet_PubnubChannel.prototype.NextMessage = function()
{
  // --- returns a message if there is one ---
  if( this.messages.length > 0 )
    return this.messages.shift();
}

MNet_PubnubChannel.prototype.ChannelID = function()
{
  // --- returns name of channel ---
  return this.channel;
}

MNet_PubnubChannel.prototype.Unsubscribe = function()
{
  PUBNUB.unsubscribe( { channel : this.channel } );
}

MNet_Pubnub = function()
{
}

// functions
MNet_Pubnub.prototype.Init = function( publishKey, subscribeKey, secretKey, sslOn )
{
  // --- start the pubnub runtime ---
  _pubnubChannel = null;
  _pubnubPublishKey = publishKey;
  _pubnubSubscribeKey = subscribeKey;

  // create config div
  var config = document.createElement( "div" );
  config.setAttribute( "pub-key", _pubnubPublishKey );
  config.setAttribute( "sub-key", _pubnubSubscribeKey );
  if( sslOn )
    config.setAttribute( "ssl", "on" );
  else
    config.setAttribute( "ssl", "off" );
  config.setAttribute( "origin", "pubsub.pubnub.com" );
  config.setAttribute( "id", "pubnub" );

  // append the config to the body
  document.body.appendChild( config );

  var script = document.createElement( "script" );
  script.setAttribute( "language", "javascript" );
  script.setAttribute( "src", "http://cdn.pubnub.com/pubnub-3.1.min.js" );

  // setup load events
  if( script.readyState )
  {
    // internet explorer
    script.onreadystatechange = function()
    {
      if( script.readyState == "loaded" || script.readyState == "complete" )
      {
        script.onreadystatechange = null;
        _pubnubStartCallback();
      }
    };
  }
  else
  {
    //good browsers
    script.onload = function()
    {
      _pubnubStartCallback();
    };
  }

  // append the script to the body
  document.body.appendChild( script );
}

MNet_PubnubLoaded = function()
{
  // --- returns true if pubnub is loaded ---
  return _pubnubInitSuccess;
}

MNet_Pubnub.prototype.Subscribe = function( channel )
{
  // --- subscribe to a channel and return the channel object ---
  if( _pubnubChannel )
    _pubnubChannel.Unsubscribe();
  _pubnubChannel = new MNet_PubnubChannel( channel );
}

MNet_Pubnub.prototype.GetChannel = function()
{
  return _pubnubChannel;
}

function _pubnubStartCallback()
{
  // --- callback after verfied script is in place ---
  _pubnubInitSuccess = true;
  PUBNUB.ready();
}
